package ie.flax.flaxengine.client.Graphic; import ie.flax.flaxengine.client.FEntity; import ie.flax.flaxengine.client.FLog; import ie.flax.flaxengine.client.FVector; import ie.flax.flaxengine.client.events.CameraUpdateEvent; import ie.flax.flaxengine.client.events.EventBus; /** * FCamera controls the viewport of a map. It allows for only what the user is looking at to be rendered instead of the whole * map making for good performance boost. * * @author Ciaran McCann * */ public class FCamera { private transient FVector position; private transient int width; private transient int height; private transient int mapWidth; private transient int mapHeight; private transient FVector interpolation; private transient Directoin interpolationDirection; public enum Directoin { NORTH, SOUTH, EAST, WEST} /** * The position is the vector at the top left hand corner * The width and the height define the viewport of the map<br> * <br>Most of the time the width and height will be the same as the canvas width and height * @param position * @param width * @param height * @param mapWidth * @param mapHeight */ public FCamera(FVector position, int width, int height) { this.interpolation = new FVector(0, 0); this.position = position; this.width = width; this.height = height; FLog.trace(this.toString() + " Was created "); EventBus.handlerManager.fireEvent(new CameraUpdateEvent()); /** * These are not set in the constructor as due to the JSON deserialising * method when a map is constructed it will call its set width and height. * So a call to the camera is made at that time. */ //FIXME: Actually this needs to be changed, as what happens when more the one map is loaded, will do for the mo. //this.mapWidth = mapWidth; //this.mapHeight = mapHeight; } /** * Not yet implemented * @param x * @param y */ public void panTo(int x, int y, int speed) { //TODO implement for in-game sinmetics } /** * Allows the camera the be centered on a entity and pan with easing. * * <br><br> * This method should be called when the entity moves, it caluates should the camera move. * It also eases the camera across with a smooth translation * * @param entity - Entity which the camera will center on * @param direction - direction that entity is moving */ public void panCentered(FEntity entity, Directoin direction ) { /** * READ ME * This method is quite complex, look at the * first if block for step by step instructions */ int cameraSpeed = entity.getSpeed(); if(direction == Directoin.EAST) // check direction camera is to pan in { // check if this is the direction the entity was moving in, at the last call of this method if(interpolationDirection != direction) { interpolationDirection = direction; interpolation.x = 0; } //below if checks basically if the entity is in the center of the drawingspace if (entity.getX() + entity.getWidth() - this.getX() > (this.getWidth() / 2)) { //if the camera was sucessfully set to the next value, if so do translate pan. If not you have reached a border of the map if(this.incrementX(cameraSpeed)) { //FIXME - CIARAN magic numbers if (this.getX() % 32 != 0) { interpolation.x += cameraSpeed * -1; //Interpolation.x is used in a GLTranslate call to achieve the interpolation } else { interpolation.x += interpolation.x * -1; //Thisa then sets it back when the full tile can be seen } } } } else if (direction == Directoin.WEST) { if(interpolationDirection != direction) { interpolationDirection = direction; interpolation.x = 0; } if (entity.getX() + entity.getWidth() - this.getX() < (this.getWidth() / 2)) { if (this.getX() % 32 != 0) { interpolation.x += cameraSpeed; } else { interpolation.x += interpolation.x * -1; } this.incrementX(cameraSpeed * -1); } } else if (direction == Directoin.SOUTH) { if(interpolationDirection != direction) { interpolationDirection = direction; interpolation.y = 0; } if (entity.getY() + entity.getHeight() - this.getY() > (this.getHeight() / 2)) { if(this.incrementY(cameraSpeed)) { if (this.getY() % 32 != 0) { interpolation.y += cameraSpeed * -1; } else { interpolation.y += interpolation.y * -1; } } } } else if (direction == Directoin.NORTH) { if(interpolationDirection != direction) { interpolationDirection = direction; interpolation.y = 0; } if (entity.getY() + entity.getHeight() - this.getY() < (this.getHeight() / 2)) { if (this.getY() % 32 != 0) { interpolation.y += cameraSpeed; } else { interpolation.y += interpolation.y * -1; } this.incrementY(cameraSpeed * -1); } } } public FVector getInterpolation(){ return interpolation; } /** * @param mapWidth the mapWidth to set */ public void setMapWidth(final int mapWidth) { this.mapWidth = mapWidth; this.mapWidth += 1; } /** * @param mapHeight the mapHeight to set */ public void setMapHeight(final int mapHeight) { this.mapHeight = mapHeight; } public int getMapWidth() { return mapWidth; } public int getMapHeight() { return mapHeight; } /** * @param width the width to set */ public void setWidth(int width) { this.width = width; FLog.trace(this.toString() + " setWidth(int " + this.width + ") PX "); } /** * @return the width */ public int getWidth() { return width; } /** * @return the height */ public int getHeight() { return height; } /** * @param height the height to set */ public void setHeight(int height) { this.height = height; FLog.trace(this.toString() + " setHeight(int " + this.height + ") PX "); } /** * Gets the camera's x position * @return */ public double getX() { return position.x; } /** * Gets the camera's y position * @return */ public double getY(){ return position.y; } /** * Sets the cameras x position, though first it checks * is the input valid * @param x */ public boolean setX(double x) { //FIXME CIARAN - magic number, only for testing will change at some piont if(x <= (mapWidth*32)-(width)&& x >= 0) { position.x = x; FLog.trace(this.toString() + " setX(double " + position.x + ") "); return true; }else{ FLog.warn("Unable to set " + this.toString() + " setX(double " + x + ") "); return false; } } /** * Sets the cameras y position, though first it checks * is the input valid * @param y */ public boolean setY(double y) { //FIXME CIARAN - magic number, only for testing will change at some piont if(y <= (mapHeight*32)-(height)&& y >= 0) { position.y = y; FLog.trace(this.toString() + " setY(double " + position.y + ") "); return true; }else{ FLog.warn("Unable to set " + this.toString() + " setY(double " + y + ") "); return false; } } /** * Increments the x position by provided amount * @param x */ public boolean incrementX(double x) { return setX(x+position.x); } /** * Increments the y position by provided amount * @param y */ public boolean incrementY(double y) { return setY(y+position.y); } }